package com.wy2.generator;

import java.io.File;
import java.sql.Connection;
import java.sql.SQLException;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;


import cn.xo68.core.PropertiesDocument;
import cn.xo68.core.date.DateTime;
import cn.xo68.core.date.TimeSpan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.wy2.generator.config.DatabaseConsts;
import com.wy2.generator.config.GeneratorConsts;
import com.wy2.generator.database.JdbcConnectionConfiguration;
import com.wy2.generator.database.JdbcConnectionFactory;
import com.wy2.generator.database.JdbcMetaDataResolver;
import com.wy2.generator.database.JdbcMetaDataResolverDefaultImpl;
import com.wy2.generator.database.MetaDataFactory;
import com.wy2.generator.database.common.DatabaseMetaDataEntity;
import com.wy2.generator.database.entity.DatabaseTable;
import com.wy2.generator.resource.Messages;

/**
 * 基于数据库表的生成器
 * @author nnsword
 * @date 2017-12-20 20:47:56
 *
 */
public class GeneratorByJdbcConnection {
	private static final Logger logger=LoggerFactory.getLogger(GeneratorByJdbcConnection.class);
	
	private final PropertiesDocument propertiesDocument;
	private final GeneratorByTable generatorByTable;
	private final JdbcMetaDataResolver jdbcMetaDataResolver;
	
	protected JdbcConnectionConfiguration jdbcConnectionConfiguration;
	protected Connection conn=null;
	protected MetaDataFactory metaDataFactory=null;
	
	
	/**
	 * @return the templateDirectory
	 */
	public File getTemplateDirectory() {
		return generatorByTable.getTemplateDirectory();
	}

	/**
	 * @return the outputRootDirectory
	 */
	public File getOutputRootDirectory() {
		return generatorByTable.getOutputRootDirectory();
	}

	/**
	 * 
	 * @param generatorByTable
	 * @param propertiesDocument
	 * @param jdbcMetaDataResolver
	 */
	public GeneratorByJdbcConnection(GeneratorByTable generatorByTable,PropertiesDocument propertiesDocument,JdbcMetaDataResolver jdbcMetaDataResolver) {
		super();
		this.generatorByTable = generatorByTable;
		this.propertiesDocument=propertiesDocument;
		if(jdbcMetaDataResolver!=null) {
			this.jdbcMetaDataResolver=jdbcMetaDataResolver;
		}else {
			this.jdbcMetaDataResolver=new JdbcMetaDataResolverDefaultImpl();
		}
		
	}
	
	public GeneratorByJdbcConnection(PropertiesDocument propertiesDocument) {
		this.propertiesDocument=propertiesDocument;
		String templateDirectory=propertiesDocument.getProperty(GeneratorConsts.GENERATOR_CONFIG_TEMPLATE_DIRECTORY);
		String outputRootDirectory=propertiesDocument.getProperty(GeneratorConsts.GENERATOR_CONFIG_OUTPUT_DIRECTORY);
		String markerTemplateString=propertiesDocument.getProperty(GeneratorConsts.GENERATOR_CONFIG_MARKER_TEMPLATE);
		String encoding=propertiesDocument.getProperty(GeneratorConsts.GENERATOR_CONFIG_ENCODING);
		String suffix=propertiesDocument.getProperty(GeneratorConsts.GENERATOR_CONFIG_TEMPLATE_SUFFIX,GeneratorConsts.GENERATOR_CONFIG_TEMPLATE_SUFFIX_DEFAULT);
		DefaultGenerator generator=new DefaultGenerator(new File(templateDirectory),new File(outputRootDirectory),markerTemplateString,encoding);
		GeneratorByTable generatorByTable=new GeneratorByTable(generator,suffix);
		this.generatorByTable = generatorByTable;
		this.jdbcMetaDataResolver=new JdbcMetaDataResolverDefaultImpl();
	}
	

	
	/**
	 * 从配置中取表前缀
	 * @date 2017-12-20 21:30:25
	 * @return
	 */
	protected String[] getTablePrefixs() {
		String tablePrefix=propertiesDocument.getProperty(DatabaseConsts.PROPERTIES_TABLE_PREFIX, DatabaseConsts.PROPERTIES_TABLE_PREFIX_Default);
		String[] prefixs=tablePrefix.split(GeneratorConsts.PROPERTIES_ARRAY_SPLIT);
		logger.info("表前缀: {}", prefixs);
		return prefixs;
	}
	
	protected JdbcConnectionConfiguration getJdbcConnectionConfiguration() {
		if(jdbcConnectionConfiguration==null) {
			jdbcConnectionConfiguration=new JdbcConnectionConfiguration();
	        jdbcConnectionConfiguration.load(propertiesDocument);
		}
		return jdbcConnectionConfiguration;
	}
	protected Connection getConnection() {
		if(conn==null) {			
	        JdbcConnectionFactory jdbcConnectionFactory=new JdbcConnectionFactory(getJdbcConnectionConfiguration());
	        try {
				conn = jdbcConnectionFactory.getConnection();
			} catch (SQLException e) {
				logger.error(Messages.getString("SQLException.0", getJdbcConnectionConfiguration()), e);
			}
		}		
		return conn;
	}
	
	protected MetaDataFactory getMetaDataFactory() {
		if (metaDataFactory==null) {
			metaDataFactory=new MetaDataFactory(getConnection(), getJdbcConnectionConfiguration().getCatalog(), getJdbcConnectionConfiguration().getSchema());
		}
		return metaDataFactory;
	}
	
	public List<DatabaseTable> listTable(String tableName){
		List<DatabaseTable> dbtables=null;
		try {
			DateTime beginDate=DateTime.Now();
			dbtables = getMetaDataFactory().builderTables(tableName,jdbcMetaDataResolver,getTablePrefixs());
			DateTime endDate=DateTime.Now();
			TimeSpan timeSpan = endDate.Substract(beginDate);
			logger.info(Messages.getString("GeneratorByJdbcConnection.1",dbtables.size(),timeSpan.getTotalseconds()));
		} catch (SQLException e) {
			logger.error(Messages.getString("SQLException.1", tableName), e);
		}finally {
			getMetaDataFactory().close(); 
        }
		return dbtables;
	}
	//DatabaseMetaDataEntity
	public DatabaseMetaDataEntity getDatabaseMetaDataEntity(String tableName){
	    DatabaseMetaDataEntity databaseMetaDataEntity=null;
        try {
            DateTime beginDate=DateTime.Now();
            databaseMetaDataEntity = getMetaDataFactory().builderDatabaseMetaDataEntity(tableName,jdbcMetaDataResolver,getTablePrefixs());
            DateTime endDate=DateTime.Now();
            TimeSpan timeSpan = endDate.Substract(beginDate);
            logger.info(Messages.getString("GeneratorByJdbcConnection.1",databaseMetaDataEntity.getTables().size(),timeSpan.getTotalseconds()));
        } catch (SQLException e) {
            logger.error(Messages.getString("SQLException.1", tableName), e);
        }finally {
            getMetaDataFactory().close(); 
        }
        return databaseMetaDataEntity;
    }


	public LinkedList<GenerateResult> generte(String tableName,Map<String,Object> model,Boolean override) {
		Map<String,Object> attris=propertiesDocument.getMap(GeneratorConsts.GENERATOR_CONFIG_TEMPLATE_ATTRIBUTE_PREFIX, true);
		if(model!=null) {
			attris.putAll(model);			
		}
		List<DatabaseTable> dbtables=listTable(tableName);
		LinkedList<GenerateResult> generateResults = generatorByTable.generate(dbtables, attris,override);
		logger.info(Messages.getString("GeneratorByJdbcConnection.0",dbtables.size()));
		return generateResults;
	}
	
	public LinkedList<GenerateResult> generteByTables(List<DatabaseTable> tables,Map<String,Object> model,Boolean override) {
	    if(tables==null || tables.isEmpty()) {
	        logger.warn("tables is empty");
	        return null;
	    }
        Map<String,Object> attris=propertiesDocument.getMap(GeneratorConsts.GENERATOR_CONFIG_TEMPLATE_ATTRIBUTE_PREFIX, true);
        if(model!=null) {
            attris.putAll(model);           
        }
        LinkedList<GenerateResult> generateResults = generatorByTable.generate(tables, attris,override);
        logger.info(Messages.getString("GeneratorByJdbcConnection.0",tables.size()));
        return generateResults;
    }
	public LinkedList<GenerateResult> getGenerateFiles(List<DatabaseTable> tables,Map<String,Object> model) {
        if(tables==null || tables.isEmpty()) {
            logger.warn("tables is empty");
            return null;
        }
        Map<String,Object> attris=propertiesDocument.getMap(GeneratorConsts.GENERATOR_CONFIG_TEMPLATE_ATTRIBUTE_PREFIX, true);
        if(model!=null) {
            attris.putAll(model);           
        }
        LinkedList<GenerateResult> generateResults = generatorByTable.getGenerateFiles(tables, attris);
        logger.info(Messages.getString("GeneratorByJdbcConnection.0",tables.size()));
        return generateResults;
    }
}
